#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ui->label->installEventFilter(this);
    ui->label_color->installEventFilter(this);
    ui->lineEdit->setText("F:/ResearchData/label/DSM_9cm_matching.png");
    ui->label->setMouseTracking(true);
    this->originImage = new QImage();
    this->showImage = new QImage();
    view_width = ui->label->width();
    view_height = ui->label->height();
    n = 4;
    row_center = floor(float(view_width) / 2) ;
    col_center = floor(float(view_height) / 2) ;
    MarkColor markcolor;
    markcolor.label = ui->spinBox_Value->value();
    defaultLabelColor = qRgb(255,255,255);
    setLabelColor(ui->label_color,defaultLabelColor);
    markcolor.color=defaultLabelColor;
    markColors.push_front(markcolor);
    loaded = false;
    markstyle = false;
}

MainWindow::~MainWindow()
{
    delete ui;
}

bool MainWindow::eventFilter(QObject *o, QEvent *e)
{
    if(QString(o->metaObject()->className()) == "QLabel")
    {
        if (  (o->objectName()=="label") && (e->type() == QEvent::MouseMove ))
        {
            //Display current point's origion pic pos.
            QMouseEvent *event = (QMouseEvent*)e;
            QPoint point = getOriginPos(event->x(),event->y());
            int row = point.x()+1;
            int col = point.y()+1;
            ui->label_origin_pos->setText("Origin("+QString::number(row)+","+QString::number(col)+")");
        }
        else if ( (o->objectName()=="label_color")&&(e->type() == QEvent::MouseButtonRelease))
        {
            QColorDialog *colorDialog = new QColorDialog(this);
            colorDialog->setWindowTitle(tr("Open Image"));
            if(colorDialog->exec() == QDialog::Accepted) {
                QColor color = colorDialog->selectedColor();
                MarkColor markcolor;
                markcolor.label = ui->spinBox_Value->value();
                markcolor.color = Color2Rgb(color);
                int lookresult = markColors.indexOf(markcolor);
                markColors.remove(lookresult);
                markColors.push_front(markcolor);
                setLabelColor(ui->label_color,markcolor.color);
            }
        }
    }
    return QWidget::eventFilter(o, e);
}
void MainWindow::keyPressEvent(QKeyEvent *key)
{
    if (key->key() == Qt::Key_Control) markstyle=!markstyle;
    if (markstyle) ui->label_markstyle->setText("Line");
    else ui->label_markstyle->setText("Point");
}

void MainWindow::mousePressEvent(QMouseEvent *event)
{
    QPoint point =  getMousePos(event->x(),event->y());
    move_start_x = point.x();
    move_start_y = point.y();
}
void MainWindow::mouseReleaseEvent(QMouseEvent *event)
{
    if (!checkMousePos(event->x(),event->y())) return;
    QPoint point =  getMousePos(event->x(),event->y());
    move_end_x = point.x();
    move_end_y = point.y();
    if ((move_end_x==move_start_x)&&(move_end_y==move_start_y))
    {
        QPoint point = getOriginPos(move_end_x,move_end_y);
        if (mark_start_point.isNull()) mark_start_point=point;
        if (markstyle)
            addMarkPoint(mark_start_point,point,ui->spinBox_Value->value());
        else
            addMarkPoint(point,point,ui->spinBox_Value->value());
        mark_start_point = point;
        updateView();
    }
}
void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
    QPoint point =  getMousePos(event->x(),event->y());
    move_dx = point.x()-move_start_x;
    move_dy = point.y()-move_start_y;
    row_center = row_center - move_dx;
    col_center = col_center - move_dy;
    updateView();
}

void MainWindow::updateView()
{
    if (!loaded) return;
    fixPos();
    showImage = new QImage(view_width,view_height,QImage::Format_ARGB32);
    int row_start = max(row_center - floor(float(view_width)/2),1);
    int col_start = max(col_center - floor(float(view_height)/2),1);
    for (int i = 0;i < view_width; i++)
        for (int j = 0;j < view_height; j++)
        {
            int row = floor((float(row_start)+i)/n);
            int col = floor((float(col_start)+j)/n);
            showImage->setPixel(i,j,originImage->pixel(row,col));
        }
    QPainter painter(showImage);
    for (int i =0;i<markPoints.count();i++)
    {
        int index = markPoints.at(i).index;
        int row = floor(float(index / origin_width)) * n;
        int col = (index % origin_width) * n;
        int row_draw = row - row_start;
        int col_draw = col - col_start;
        if ( (row_draw<0)||(row_draw>view_width-1) ||(col_draw<0)||(col_draw>view_height-1))
            continue;
        painter.setPen(QPen(getMarkColor(markPoints.at(i).label)));
        painter.drawRect(row_draw,col_draw,n,n);
    }
    ui->label->setPixmap(QPixmap::fromImage(*showImage));
}

void MainWindow::setLabelColor(QLabel *label,QRgb rgb)
{
    if (!label->autoFillBackground())
        label->setAutoFillBackground(true);
    QPalette p = label->palette();
    p.setColor(QPalette::Background,rgb);
    label->setPalette(p);
}

bool MainWindow::checkn(int n)
{
    int resize_width_ = origin_width * n;
    int resize_height_ = origin_height * n;
    if((resize_width_<view_width)||(resize_height_<view_height))
    {
        return false;
    }
    return true;
}

void MainWindow::addMarkPoint(QPoint startPoint, QPoint endPoint, int label)
{
    QVector<QPoint> points = getPoints(startPoint,endPoint);
    for (int i=0;i<points.count();i++)
    {
        MarkPoint markPoint;
        markPoint.index =  points.at(i).x()*origin_width+points.at(i).y();
        markPoint.label =  label;
        int lookresult = markPoints.indexOf(markPoint);
        if (lookresult == -1)
            markPoints.push_front(markPoint);
        else
            if ((points.count()==1)||(points.at(i)!=startPoint))
               markPoints.remove(lookresult);
    }
}

QVector<QPoint> MainWindow::getPoints(QPoint startPoint,QPoint endPoint)
{
    QVector<QPoint> points;
    if (startPoint==endPoint)
    {
        points.push_back(startPoint);
        return points;
    }
    int vx = (startPoint.x()>endPoint.x())?(-1):1;
    int vy = (startPoint.y()>endPoint.y())?(-1):1;
    int width = abs(startPoint.x()-endPoint.x())+1;
    int height = abs(startPoint.y()-endPoint.y())+1;
    int hwidth = floor((float)width/2);
    int hheight = floor((float)height/2);
    int newx,newy;
    if (width>height)
    {
        for(int i=1;i<hwidth;i=i+1)
        {
            newx = startPoint.x()+i*vx;
            newy = startPoint.y()+floor(((float)i / hwidth)*hheight) * vy;
            points.push_back(QPoint(newx,newy));
            newx = endPoint.x()-i*vx;
            newy = endPoint.y()-floor(((float)i / hwidth)*hheight) * vy;
            points.push_back(QPoint(newx,newy));
        }
        if ((hwidth*2)!=width)
        {
            newx = startPoint.x()+hwidth*vx;
            newy = startPoint.y()+hheight*vy;
            points.push_back(QPoint(newx,newy));
        }
    }else{
        for(int i=1;i<hheight;i=i+1)
        {
            newx = startPoint.x()+floor(((float)i / hheight)*hwidth)*vx;
            newy = startPoint.y()+i*vy;
            points.push_back(QPoint(newx,newy));
            newx = endPoint.x()-floor(((float)i / hheight)*hwidth)*vx;
            newy = endPoint.y()-i*vy;
            points.push_back(QPoint(newx,newy));
        }
        if ((hheight*2)!=height)
        {
            newx = startPoint.x()+hwidth*vx;
            newy = startPoint.y()+hheight*vy;
            points.push_back(QPoint(newx,newy));
        }
    }
    points.push_back(endPoint);
    points.push_back(startPoint);
    return points;
}

void MainWindow::fixPos()
{
    //fix center pos to adjust edge .
    row_center = max(row_center, floor(float(view_width)/2));
    col_center = max(col_center, floor(float(view_height)/2));
    row_center = min (row_center,resize_width-floor(float(view_width)/2));
    col_center = min (col_center,resize_height-floor(float(view_height)/2));
}
QRgb MainWindow::getMarkColor(int label)
{
    MarkColor markcolor;
    markcolor.label = label;
    int lookresult = markColors.indexOf(markcolor);
    return markColors.at(lookresult).color;
}

QPoint MainWindow::getMousePos(int x,int y)
{
    //Adjust MainForm Mouse Pos to Label Mouse Pos.
    QPoint mousePoint ;
    mousePoint.setX(min(max(x-ui->label->x(),0),ui->label->width()-1));
    mousePoint.setY(min(max(y-ui->label->y(),0),ui->label->height()-1));
    return mousePoint;
}
bool MainWindow::checkMousePos(int x,int y)
{
    if (x-ui->label->x()<0) return false;
    if (x-ui->label->x()>ui->label->width()-1) return false;
    if (y-ui->label->y()<0) return false;
    if (y-ui->label->y()>ui->label->height()-1) return false;
    return true;
}
QPoint MainWindow::getOriginPos(int x,int y)
{
    //Get Origin pic Pos from View Pos
    QPoint point;
    int row_start = max(row_center - floor(float(view_width)/2),1);
    int col_start = max(col_center - floor(float(view_height)/2),1);
    int row = floor(float(row_start+x)/n);
    int col = floor(float(col_start+y)/n);
    point.setX(row);
    point.setY(col);
    return point;
}

void MainWindow::on_pb_Load_clicked()
{
    //Load Picture that need to be labeled
    originImage->load(ui->lineEdit->text());
    if (originImage->isNull())
    {
        QMessageBox::information(this,"Error","Can't Open File.."+ui->lineEdit->text());
        return;
    }
    loaded = true;

    //Init view
    origin_width = originImage->width();
    origin_height = originImage->height();
    while(!checkn(n)) n++;
    resize_width = origin_width * n;
    resize_height = origin_height * n;
    updateView();
}

void MainWindow::on_pb_selectFile_clicked()
{
    QFileDialog *fileDialog = new QFileDialog(this);
    fileDialog->setWindowTitle(tr("Open Image"));
    fileDialog->setDirectory(".");
    if(fileDialog->exec() == QDialog::Accepted) {
        QString path = fileDialog->selectedFiles()[0];
        ui->lineEdit->setText(path);
    } else {

    }
}

void MainWindow::on_spinBox_valueChanged(int newn)
{
    if (!checkn(newn))
    {
        ui->spinBox->setValue(n);
        return;
    }
    row_center = (int) ((row_center / n) * newn);
    col_center = (int) ((col_center / n) * newn);
    n = newn;
    resize_width = origin_width * n;
    resize_height = origin_height * n;
    updateView();
}

void MainWindow::on_pb_Save_clicked()
{
    if (!loaded) return;
    QImage *resImage = new QImage(origin_width,origin_height,QImage::Format_ARGB32);
    resImage->fill(QColor(0,0,0,0));
    for (int i =0;i<markPoints.count();i++)
    {
        int index = markPoints.at(i).index;
        int row = floor(float(index / origin_width)) ;
        int col = index % origin_width;
        resImage->setPixel(row,col,getMarkColor(markPoints.at(i).label));
    }
    resImage->save("label_res.png");
    QMessageBox::information(this,"","Save Success!");
}

void MainWindow::on_spinBox_Value_valueChanged(int label)
{
    MarkColor markcolor;
    markcolor.label = label;
    int lookresult = markColors.indexOf(markcolor);
    if (lookresult==-1)
    {
        markcolor.color=defaultLabelColor;
        markColors.push_front(markcolor);
        setLabelColor(ui->label_color,defaultLabelColor);
        return;
    }
    setLabelColor(ui->label_color,markColors.at(lookresult).color);
}

void MainWindow::on_pb_Test_clicked()
{
  QVector<QPoint> points=  getPoints(QPoint(7,8),QPoint(2,3));
  qDebug()<<QString::number(points.count());
  for (int i=0;i<points.count();i++)
  {
      qDebug()<<QString::number(points.at(i).x())+","+QString::number(points.at(i).y());
  }
}
void MainWindow::on_pb_Clear_clicked()
{
    markPoints.clear();
    updateView();
}
